﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Creative85.Framework.Data;
using Project32CHE.Biz.UserAccount.Models;
using NPoco;
using System.Runtime.Caching;
using System.Security.Authentication;
using Project32CHE.Passport.Utilities;
using Project32CHE.Biz.UserAccount.Exceptions;
using Creative85.Framework.Utilities;

namespace Project32CHE.Biz.UserAccount
{
    public static class AccountService
    {
        private static void existThrow(string account)
        {
            if (Exist(account))
            {
                throw new NotSupportedException("重复的账号名！");
            }
        }

        /// <summary>
        /// 用户查询
        /// </summary>
        /// <param name="UnionID"></param>
        /// <param name="shopId"></param>
        /// <param name="criteria"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderField"></param>
        /// <returns></returns>
        public static Page<Dictionary<string, object>> Query(Guid UnionID, Guid shopId, Dictionary<string, string> criteria, int pageIndex = 1, int pageSize = 50, string orderField = null)
        {
            //将criteria转为大小写无关的字典searchDic
            var searchDic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            if (criteria != null)
            {
                foreach (var key in criteria.Keys)
                {
                    if (!searchDic.ContainsKey(key))
                    {
                        searchDic.Add(key, criteria[key]);
                    }
                }
            }
            var sql = new SqlBuilder();
            var sqlTpl = sql.AddTemplate(@"
select * from (select
 u.Id,u.Name,u.Code,u.Phone,u.Gender,u.Dept,u.CreateTime,
 a.Name as AccountName
 from Users u LEFT JOIN Accounts a ON u.Id=a.UserId
 where /**where**/ ) t /**orderby**/");
            sql.Where("u.UnionID=@0", UnionID);
            if (!shopId.Equals(Guid.Empty)) sql.Where("u.shopId  = @0 ", shopId);
            var sqlParts = new string[][] {
                new string[]{"Name","u.Name like @0","%{0}%"},
                 new string[]{"Code","u.Code = @0","{0}"},
                new string[] { "Dept", "u.Dept like @0", "%{0}%" },
            };
            foreach (var sqlPart in sqlParts)
            {
                string value = null;
                if (searchDic.ContainsKey(sqlPart[0]))
                {
                    value = searchDic[sqlPart[0]];
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        continue;
                    }
                    if (sqlPart.Length > 2)
                    {
                        value = string.Format(sqlPart[2], value);
                    }

                    sql.Where(sqlPart[1], value);
                }
            }
            if (!string.IsNullOrWhiteSpace(orderField))
            {
                sql.OrderBy(orderField);
            }
            return Db.Instance.Page<Dictionary<string, object>>(pageIndex, pageSize, sqlTpl);
        }

        public static bool Exist(string account)
        {
            return Db.Instance.Query<User>().Where(x => x.AccountName.Equals(account)).ToList().Any();
        }
        public static List<Account> Get(Guid userId)
        {
            var list = Db.Instance.Query<Account>().Where(x => x.UserId == userId).ToList();
            return list;
        }
        public static Account Get(string account)
        {
            var model = Db.Instance.Query<Account>().Where(x => x.Name.Equals(account)).Single();
            return model;
        }

        private readonly static TimeSpan FailAttemptTimeSpan = new TimeSpan(0, 30, 0);
        private readonly static int FailAttemptMaxCount = 10;

        #region 登录注销、验证相关
        public static void LoginValidate(string accountName, string accountPass, out Guid userId)
        {
            User account = null;
            Snapshot<User> snapshot = null;
            var accounts = Db.Instance.Query<User>().Where(x => x.AccountName == accountName).ToList();
            account = accounts.SingleOrDefault();
            if (account == null) { throw new AccountNotFoundException(accountName); }
            snapshot = Db.Instance.StartSnapshot(account);
            try
            {
                if (account.FailAttemptExpired > DateTime.Now && account.FailAttemptCount >= FailAttemptMaxCount)
                {
                    throw new InvalidCredentialException();
                }
                using (var encrypt = new EncryptOperator(account.PasswordSale))
                {
                    bool b = encrypt.Check(accountPass, account.PasswordCipher);
                    if (!b)
                    {
                        //更新失败计数与过期时间
                        if (account.FailAttemptCount == 0 || account.FailAttemptExpired < DateTime.Now)
                        {
                            account.FailAttemptExpired = DateTime.Now.Add(FailAttemptTimeSpan);
                        }
                        account.FailAttemptCount += 1;

                        if (account.FailAttemptCount >= FailAttemptMaxCount)
                        {
                            throw new InvalidCredentialException();
                        }
                        else
                        {
                            throw new AuthenticationException("密码不正确！");
                        }
                    }
                }
                account.FailAttemptCount = 0;
                account.FailAttemptExpired = DateTime.Now;
                if (account.AccountState)
                {
                    throw new AuthenticationException("账号已被禁用，请联系管理员！");
                }
                account.LastLoginTime = DateTime.Now;
            }
            catch (InvalidCredentialException e)
            {
                throw new InvalidCredentialException("尝试次数超过系统限制，请稍后重试！", e);
            }
            finally
            {
                //更新
                if (snapshot != null)
                {
                    Db.Instance.Update(account, snapshot.UpdatedColumns());
                }
            }
            userId = account.Id;
        }
        #endregion
    }
}
